import time

from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
from fastapi.responses import StreamingResponse
from weaviate.collections.classes.config import Configure, Property, DataType
from weaviate.collections.classes.filters import Filter
import json

import config
from auth_service.auths import verify_token
from query.services import rags_query
from tables.chat_history import ChatHistories
from tables.faq import FAQ_DB
from tables.feedback import Feedbacks
from tables.file import Files
from tables.preset_problem import PreProblems
from tables.vector import Vectors
from utils.main import str_to_hash, get_embedding
from typing import List, Optional
from fastapi import APIRouter, UploadFile, File, HTTPException, Depends, Query, Form
from query.services import upload
from file.services import delete_local_file

router = APIRouter(
    prefix="/rag/query",
    tags=["query"],
    responses={404: {"description": "Not found"}}
)


class Query(BaseModel):
    query: str
    faq_id: int
    # rag_ids: list[str]
    # llm: str
    # is_preset_query: bool = False
    # # 查询拓展，1：无
    # query_expansion: int = 1
    # # 推荐问题
    # is_recommend_query: bool = False
    # stream: bool = False
    # temperature: float = 0.2


@router.post("/query", summary="问答")
async def query_api(
        body: Query,
        current_user=Depends(verify_token)
):
    try:
        res = FAQ_DB.get_faq_detail_api(body.faq_id)
        if not res:
            raise Exception("未检索到问答信息")
        rag_ids = res.rags.split(",")

        return StreamingResponse(
            rags_query(
                collection_name=str_to_hash(current_user.username),
                # collection_name=str_to_hash("test"),
                userid=current_user.id,
                # userid=1,
                query=body.query,
                rag_ids=rag_ids,
                llm=res.llm,
                is_preset_query=False,
                query_expansion=1,
                is_recommend_query=False,
                stream=False,
                temperature=0.2,
            ),
            media_type="text/event-stream",
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/delete_preset_problem", summary="删除预设问题")
async def delete_preset_problem_api(
        problem_id: int,
        current_user=Depends(verify_token)
):
    try:
        # 删除预设问题
        res = PreProblems.delete_preset_problem_by_id(userid=current_user.id, id=problem_id)
        if not res:
            raise Exception("删除失败")
        # 删除向量库数据
        await Vectors.delete_chunks(
            collection_name=str_to_hash(current_user.username),
            source=problem_id,
        )
        return {"code": 200, "message": "删除成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.delete("/delete_problem_by_fileid", summary="根据文件id删除预设问题")
async def delete_preset_problem_all_api(
        file_id: int,
        current_user=Depends(verify_token)
):
    try:
        problems = PreProblems.get_preset_problems_by_fileid(file_id)
        for problem in problems:
            # 删除向量库数据
            await Vectors.delete_chunks(
                collection_name=str_to_hash(current_user.username),
                source=problem.id,
            )
        file_info = Files.get_file_by_id(file_id)

        # 删除db文件信息
        res_db = Files.del_file_by_id(file_id)
        if not res_db:
            raise Exception("文件db信息删除失败")
        # 删除本地文件
        res_local = delete_local_file(file_info.filepath)
        if not res_local:
            raise Exception("本地文件删除失败")

        # 删除预设问题
        res = PreProblems.delete_file_preset_problem_by_id(file_id,current_user.id)
        if not res:
            raise Exception("预设问题删除失败")

        return {"code": 200, "message": "删除成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

class UpdatePresetProblem(BaseModel):
    id: int
    query: str = None
    answer: str = None
    stop: bool = False


@router.put("/update_preset_problem", summary="更新预设问题")
async def update_preset_problem_api(
        body: UpdatePresetProblem,
        current_user=Depends(verify_token)
):
    try:
        # 修改预设问题
        res = PreProblems.update_preset_problem_by_id(
            userid=current_user.id,
            id=body.id,
            query=body.query,
            answer=body.answer,
            stop=body.stop
        )
        if not res:
            raise Exception("更新失败")
        # 获取向量库文本块uuid
        collection_name = str_to_hash(current_user.username)
        chunk_info = await Vectors.get_chunk_by_filter(
            collection_name=collection_name,
            filters=Filter.by_property("source").equal(body.id),
        )
        if chunk_info:
            chunk_id = chunk_info[0].uuid
            # 修改向量库数据
            if body.query is None and body.answer is None:
                await Vectors.update_chunk_generic(
                    collection_name=collection_name,
                    chunk_id=chunk_id,
                    properties={
                        "stop": body.stop
                    },
                    vector={}
                )
            else:
                await Vectors.update_chunk_generic(
                    collection_name=collection_name,
                    chunk_id=chunk_id,
                    properties={
                        "query": body.query,
                        "answer": body.answer,
                        "stop": body.stop
                    },
                    vector={
                        "query": (await get_embedding(model=config.default_embed, text=body.query))[0],
                        "answer": (await get_embedding(model=config.default_embed, text=body.answer))[0],
                    }
                )
        return {"code": 200, "message": "更新成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/get_preset_problems", summary="获取预设问题")
async def get_preset_problem_api(
        faq_id: str ,
        query: str = None,
        limit: int = None,
        offset: int = None,
        current_user=Depends(verify_token)
):
    try:
        res = PreProblems.get_preset_problems(faq_id,query,limit,offset,userid=current_user.id)

        return {"code": 200, "message": "预设问题获取成功","total_count": res.total_count,"data":res.data }

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/get_preset_problems_detail", summary="根据文件id获取预设问题")
async def get_preset_problem_api(
        file_id: int,
        query:str = None,
        limit:int = 10,
        offset:int = 0,
        current_user=Depends(verify_token)
):
    try:
        res = PreProblems.get_preset_problems_detail(file_id, query,limit,offset,userid=current_user.id)

        return {"code": 200, "message": "文档预设问题详情获取成功","total_count": res.total_count,"data": res.data}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/get_preset_problems_by_faq", summary="根据问答id获取预设问题")
async def get_preset_problem_by_faq_api(
        faq_id: int,
        limit:int = 10,
        offset:int = 0,
        current_user=Depends(verify_token)
):
    try:
        res = PreProblems.get_preset_problems_by_faq(faq_id,limit,offset)

        return {"code": 200, "message": "文档预设问题详情获取成功","data": res}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

class CreatePresetProblem(BaseModel):
    query: str
    answer: str


@router.post("/create_preset_problem", summary="创建预设问题")
async def create_preset_problem_api(
        files: List[UploadFile] = File(...),
        faq_id: str = Form(None),
        current_user=Depends(verify_token)
):
    pre_id = None
    try:
        problems =  await upload(files,faq_id,current_user)

        # 检查是否已创建向量集合
        collection_name = str_to_hash(current_user.username)
        if not Vectors.exists(collection_name=collection_name):
            Vectors.create_collection(
                collection_name=collection_name,
                properties=[
                    Property(name="query", data_type=DataType.TEXT),
                    Property(name="answer", data_type=DataType.TEXT),
                    Property(name="source", data_type=DataType.INT),
                    Property(name="stop", data_type=DataType.BOOL),
                ],
                vectorizer_config=[
                    Configure.NamedVectors.none(name="query"),
                    Configure.NamedVectors.none(name="answer"),
                ],
                is_base=False
            )
        # 创建预设问题
        # all_prproblems = PreProblems.create_preset_problem(
        #     userid=current_user.id,
        #     query="",
        #     answer=""
        # )
        # if not res:
        #     raise Exception("创建失败")
        # pre_id = res.id
        for res in problems:
            # 创建向量库数据
            await Vectors.create_chunk_generic(
                collection_name=str_to_hash(current_user.username),
                properties={
                    "query": res.query,
                    "answer": res.answer,
                    "source": res.id,
                    "stop": res.stop
                },
                vector={
                    "query": (await get_embedding(model=config.default_embed, text=res.query))[0],
                    "answer": (await get_embedding(model=config.default_embed, text=res.answer))[0],
                }
            )

        return {"code": 200, "message": "创建成功"}
    except Exception as e:
        # 失败删除添加的预设问题
        if pre_id is not None:
            PreProblems.delete_preset_problem_by_id(userid=current_user.id, id=pre_id)
        raise HTTPException(status_code=500, detail=str(e))

class FeedbackInfo(BaseModel):
    rating: int
    describe: str
    query: str
    answer: str
    recommend: list
    source: list

@router.post("/feedback", summary="用户反馈")
async def feedback_api(
        body: FeedbackInfo,
        current_user=Depends(verify_token)
):
    try:
        res = await Feedbacks.insert_new_feedback(
            userid=current_user.id,
            rating=body.rating,
            describe=body.describe,
            timestamp=time.time(),
            query=body.query,
            answer=body.answer,
            recommend="\n".join(body.recommend),
            source=json.dumps(body.source)
        )
        if not res:
            raise Exception("反馈失败")
        return {"code": 200, "message": "反馈成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


class CreateChatHistory(BaseModel):
    message: list

@router.post("/create_chat_history", summary="创建聊天记录")
async def create_chat_history_api(
        body: CreateChatHistory,
        current_user=Depends(verify_token)
):
    try:
        if len(body.message) < 2:
            return {"code": 200, "message": "没有对话信息，本次聊天记录不保存"}
        res = await ChatHistories.insert_new_history(
            userid=current_user.id,
            message=json.dumps(body.message),
            title=body.message[1]["content"][:20],
            update_time=time.time(),
        )
        if not res:
            raise Exception("创建失败")
        return {"code": 200, "message": "创建成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


class UpdateChatHistory(BaseModel):
    id: int
    message: list

@router.put("/update_chat_history", summary="更新聊天记录")
async def update_chat_history_api(
        body: UpdateChatHistory,
        current_user=Depends(verify_token)
):
    try:
        res = await ChatHistories.update_history(
            userid=current_user.id,
            id=body.id,
            message=json.dumps(body.message),
            update_time=time.time(),
        )
        if not res:
            raise Exception("更新失败")
        return {"code": 200, "message": "更新成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/get_chat_histories", summary="获取聊天记录列表")
async def get_chat_histories_api(
        current_user=Depends(verify_token)
):
    try:
        res = await ChatHistories.get_chat_histories(userid=current_user.id)
        res = [{"id": i.id, "title": i.title, "update_time": i.update_time} for i in res]
        return {"code": 200, "data": res, "message": "聊天记录获取成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/get_chat_history", summary="获取聊天记录")
async def get_chat_history_api(
        id: int,
        current_user=Depends(verify_token)
):
    try:
        res = ChatHistories.get_chat_history(userid=current_user.id, id=id)[0]
        res = json.loads(res.message)
        return {"code": 200, "data": res, "message": "聊天记录获取成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/delete_chat_history", summary="删除指定聊天记录")
async def delete_chat_history_api(
        id: int,
        current_user=Depends(verify_token)
):
    try:
        res = await ChatHistories.delete_chat_history(userid=current_user.id, id=id)
        if not res:
            raise Exception("删除失败")
        return {"code": 200, "message": "删除成功"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
